﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Runtime.Remoting.Contexts;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;
using TSMR01Xml;
using uniview;

namespace Rxbit.Core.Driver
{
    public class XmlTcpServerEntity
    {

        public event Action<TrafficFlow> DataReceived;

        /// <summary>
        /// 实时过车信息触发
        /// </summary>
        public event Action<TrafficEvent> TrafficEventReceived;


        // 打开本地端口，并监听       

        // 当有客户端连接到本地，开启数据接收【线程】

        // 将数据转换成XML格式，并转换到对应的类里面去


        public int LocalPort { get; set; }

        static System.Net.Sockets.TcpListener tcpListener;
        public TcpClient curentTcp;
        bool ListenState = false;

        /// <summary>
        /// 开始监听
        /// </summary>
        /// <returns></returns>
        public bool StartListen(string ip, int port = 5196)
        {
            ListenState = true;
            IPAddress iPAddress = IPAddress.Parse(ip);
            tcpListener = new System.Net.Sockets.TcpListener(iPAddress, port);
            try
            {
                tcpListener.Start();

                // 
                Task.Run(() => ListenLoop(ListenState));

                // 建立远程的接收线程
                Task.Run(() => ReceiveData());

                Task.Run(() => DealLoop());

                return true;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                return false;
            }
        }

        /// <summary>
        /// 收到101信号，通知界面
        /// </summary>
        public event Action Signal101Come;


        ManualResetEvent shutdownEvent = new ManualResetEvent(false);


        /// <summary>
        /// 接收数据线程
        /// </summary>
        private void ReceiveData()
        {
            //while (true)
            //修改为停止监听状态下不接收数据
            while (ListenState)
            {

                if (curentTcp != null)
                {
                    if (curentTcp.Client.Available > 0)
                    {
                        byte[] buffer = new byte[curentTcp.ReceiveBufferSize];

                        // 收到远程发送来的数据
                        var getCount = curentTcp.Client.Receive(buffer);

                        // 
                        byte[] data = buffer.Take(getCount).ToArray();
                        DataQueue.Enqueue(data);

                        //Console.WriteLine(GetStringFromByteArray(data));
                    }
                    else
                    {
                        if (shutdownEvent.WaitOne(1))
                        {
                            break;
                        }
                    }
                }
                else
                {
                    if (shutdownEvent.WaitOne(1000))
                    {
                        break;
                    }
                }
            }
        }

        /// <summary>
        /// 获取字符串
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        private string GetStringFromByteArray(byte[] data)
        {
            string result = "";

            for (int i = 0; i < data.Length; i++)
            {
                result = $"{result}{data[i].ToString("X2")}";
            }

            return result;
        }

        /// <summary>
        /// 处理循环
        /// </summary>
        private void DealLoop()
        {
            while (true)
            {
                byte[] dataRall;


                if (DataQueue.Count > 0)
                {
                    List<byte> DataList = new List<byte>();

                    do
                    {
                        if (DataQueue.TryDequeue(out dataRall))
                        {

                            DataList.AddRange(dataRall);
                        }

                    } while (DataQueue.Count > 0);

                    bool isFind = false;//是否找到匹配数据包

                    for (int i = 0; i < DataList.Count;)
                    {
                        // 1.找头,    如果没有数据+1继续找
                        byte[] packHead = DataList.Skip(i).Take(4).ToArray(); //包头
                        if (IsSameBytes(packHead, packageHeader))
                        {
                            // 数据包长度32位
                            UInt32 dataLen = (UInt32)(DataList[i + 4] << 24 | (DataList[i + 5] << 16) | (DataList[i + 6] << 8) | DataList[i + 7]);

                            UInt32 command = (UInt32)(DataList[12] << 24 | (DataList[13] << 16) | (DataList[14] << 8) | DataList[15]);


                            byte[] packFoot = DataList.Skip(i + 4 + 4 + Convert.ToInt32(dataLen)).Take(4).ToArray();
                            //判断包尾
                            if (IsSameBytes(packFoot, packageFooter))
                            {
                                isFind = true;

                                // 数据打包后的处理
                                ShowData(DataList.Skip(i).Take(8 + Convert.ToInt32(dataLen) + 4).ToArray());
                                i = i + 8 + Convert.ToInt32(dataLen) + 4;
                            }
                            else
                            {
                                // 等待一会儿，保证数据完整
                                //Console.WriteLine($"數據長度不夠之前：dataQueue长度{DataQueue.Count},dataRall长度{dataRall.Length},i的位置{i}");
                                if (shutdownEvent.WaitOne(500)) break;
                                do
                                {
                                    if (DataQueue.TryDequeue(out dataRall))
                                    {

                                        DataList.AddRange(dataRall);
                                    }

                                } while (DataQueue.Count > 0);
                                //Console.WriteLine($"dataQueue长度{DataQueue.Count},dataRall长度{dataRall.Length},i的位置{i}");
                                i++;
                                continue;
                            }

                        }
                        else if (isFind)
                        {
                            break;
                        }
                        else
                        {
                            i = i + 1;
                        }

                        // 2.找到文件中的数据长度字节部分，获取数据长度
                        // 3.根据数据长度和包头（16字节）去找到包尾，并判断包尾。如果有完整的包尾，则把该数据放到GetIN函数里面，然后I标记需要加datalen+16+4.如果没有找到完整的包【直接退出】
                        // 从数据里面找到一个完整地数据包
                        //GetIN("完整的包");

                    }
                }
                // 没有数据等待100ms
                else
                {
                    if (shutdownEvent.WaitOne(10)) break;
                }
            }
        }


        /// <summary>
        /// 显示或者处理打包后的数据
        /// </summary>
        /// <param name="dataRall">完整数据包</param>
        private void ShowData(byte[] dataRall)
        {
            // 数据 字节流
            //byte[] dataRall = buffer.Take(getCount).ToArray();

            //加入包头包尾判断
            //解析命令码
            Byte[] commandByte = new Byte[4];

            if (dataRall.Length < 1) return;


            // 判断数据包头包尾
            //if (IsSameBytes(dataRall.Take(4).ToArray(), packageHeader))
            {
                // 根据命令码将数据填到对应的XML解析结构中解析
                UInt32 command = (UInt32)(dataRall[12] << 24 | (dataRall[13] << 16) | (dataRall[14] << 8) | dataRall[15]);

                // 数据包长度32位

                UInt32 dataLen = (UInt32)(dataRall[4] << 24 | (dataRall[5] << 16) | (dataRall[6] << 8) | dataRall[7]);

                var xmlData = dataRall.Skip(16).Take(Convert.ToInt32(dataLen) - 8).ToArray();
                if ((dataLen - 8) == xmlData.Length)
                {

                    // 根据命令码将数据填到对应的XML解析结构中解析
                    switch (command)
                    {
                        // 联机信号（有应答） 
                        case 101:
                            Signal101Come?.Invoke();
                            break;

                        // 交通流信
                        case 107:
                            // 封装
                            TrafficFlow flow = new TrafficFlow();
                            flow.SetData(xmlData);
                            DataReceived?.Invoke(flow);
                            //TrafficFlows.Add(flow);
                            break;

                        // 实时记录信息：实时过车信息。 
                        case 6071:
                            TrafficEvent trafficEvent = new TrafficEvent();
                            trafficEvent.SetData(xmlData);
                            //List集合数量超过40，删除一个
                            //if (trafficEvents.Count > 40)
                            //{
                            //    trafficEvents.RemoveAt(0);
                            //}
                            //trafficEvents.Add(trafficEvent);
                            TrafficEventReceived?.Invoke(trafficEvent);
                            break;
                        //应答联机信号：应答收到记录信息
                        case 501:
                            ResponseInfoModel recorder = new ResponseInfoModel();
                            recorder.CamID = "abc";
                            recorder.RecordID = "xyz";
                            recorder.Result = 0;
                            recorder.ReqCmdID = 16011;
                            recorder.DBRecordID = "xxx";

                            curentTcp.Client.Send(GetResponseRecorderInfo(recorder));
                            break;
                        default:
                            break;
                    }

                }
                else
                {
                    Console.WriteLine("数据长度不够");
                }
            }
        }

        /// <summary>
        /// 有客户端链接到端口
        /// </summary>
        public event Action<TcpClient> ClientConnected;

        /// <summary>
        /// 监听线程
        /// </summary>
        private void ListenLoop(bool ListenState)
        {
            while (ListenState)
            {
                if (tcpListener.Pending())
                {
                    try
                    {
                        // 监听到一个 远程
                        var client = tcpListener.AcceptTcpClient();

                        curentTcp = client;
                        ClientConnected?.Invoke(client);
                    }
                    catch (Exception ex) { break; }
                }
                else
                {
                    if (shutdownEvent.WaitOne(100))
                    {
                        break;
                    }
                }

            }
        }
        public void StopListen()
        {
            DataReceived = null;
            ClientConnected = null;
            Signal101Come = null;
            TrafficEventReceived = null;
            DataReceived = null;
            ListenState = false;
            tcpListener.Stop();
            tcpListener = null;
            shutdownEvent.Set();
        }



        List<TrafficFlow> TrafficFlows = new List<TrafficFlow>();
        List<TrafficEvent> trafficEvents = new List<TrafficEvent>();

        /// <summary>
        /// 包头
        /// </summary>
        private byte[] packageHeader = new byte[] { 0x77, 0xAA, 0x77, 0xAA };
        /// <summary>
        /// 包尾
        /// </summary>
        private byte[] packageFooter = new byte[] { 0x77, 0xAB, 0x77, 0xAB };

        private ConcurrentQueue<byte[]> DataQueue = new ConcurrentQueue<byte[]>();


        public byte[] GetResponseRecorderInfo(ResponseInfoModel recorder)
        {
            //int packageHeaderLen

            //byte[] result = null;
            List<byte> dataList = new List<byte>();
            // 包头 ，数据长度，命令码  协议版本

            //result.Concat(packageHeader);
            //包头
            dataList.AddRange(packageHeader);


            // XML文件


            // 将XML文件转换成字符串
            string xmlStr = XmlSerialize(recorder);
            byte[] xmlByte = Encoding.ASCII.GetBytes(xmlStr);
            int dataPackLen = 4 + 4 + xmlByte.Length;
            //应答信息XML的长度
            dataList.AddRange(BitConverter.GetBytes(dataPackLen));
            //协议
            dataList.AddRange(new Byte[] { 0x00, 0x00, 0x00, 0x02 });
            //命令
            dataList.AddRange(BitConverter.GetBytes(16011));

            // 从字符串中获取字节  UTF8
            dataList.AddRange(xmlByte);

            // 包尾
            dataList.AddRange(packageFooter);
            return dataList.ToArray();
        }



        private bool IsSameBytes(byte[] source, byte[] target)
        {
            if (source.Length != target.Length) return false;
            for (int i = 0; i < source.Length; i++)
            {
                if (source[i] != target[i]) return false;
            }
            return true;
        }

        public void Close()
        { }

        /// <summary>
        /// 
        /// </summary>
        public static List<TrafficFlow> ModelAs = new List<TrafficFlow>();

        /// <summary>
        /// 将实体对象转换成XML
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <param name="obj">实体对象</param>
        public static string XmlSerialize<T>(T obj)
        {
            try
            {
                using (StringWriter sw = new StringWriter())
                {
                    Type t = obj.GetType();
                    XmlSerializer serializer = new XmlSerializer(obj.GetType());
                    serializer.Serialize(sw, obj);
                    sw.Close();
                    return sw.ToString();
                }
            }
            catch (Exception ex)
            {
                throw new Exception("将实体对象转换成XML异常", ex);
            }
        }
    }

    /// <summary>
    /// 
    /// </summary>
    public class ResponseInfoModel
    {
        /// <summary>
        /// 卡口相机编号
        /// </summary>
        public string CamID { get; set; }
        /// <summary>
        /// 记录ID号
        /// </summary>
        public string RecordID { get; set; }
        /// <summary>
        /// 错误码
        /// </summary>
        public int Result { get; set; }
        /// <summary>
        /// 请求命令码
        /// </summary>
        public int ReqCmdID { get; set; }
        /// <summary>
        /// 内部使用，数据库记录
        /// </summary>
        public string DBRecordID { get; set; }

    }
}
